//
//  NSMutableArray+SafeChecker.m
//  testAboutRT
//
//  Created by admin on 2018/2/5.
//  Copyright © 2018年 admin. All rights reserved.
//

#import "NSMutableArray+SafeChecker.h"
#import <objc/runtime.h>

@implementation NSMutableArray (SafeChecker)

// runtime会对每个类以及其每个category都发送load消息，所以使用dispatch_once代码块保证代码只执行一次
+ (void)load {
//    NSLog(@"current method: %@", NSStringFromSelector(_cmd));
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        id obj = [[self alloc] init];
        [obj swizzleOriginalMethod:@selector(addObject:) withReplaceMethod:@selector(safe_addObject:)];
        [obj swizzleOriginalMethod:@selector(removeObject:) withReplaceMethod:@selector(safe_removeObject:)];
        [obj swizzleOriginalMethod:@selector(removeObjectAtIndex:) withReplaceMethod:@selector(safe_removeObjectAtIndex:)];
        [obj swizzleOriginalMethod:@selector(insertObject:atIndex:) withReplaceMethod:@selector(safe_insertObject:atIndex:)];
        [obj swizzleOriginalMethod:@selector(objectAtIndex:) withReplaceMethod:@selector(safe_objectAtIndex:)];
    });
}

- (void)swizzleOriginalMethod:(SEL)originalSelector withReplaceMethod:(SEL)replaceSelector {
    Method originMethod = class_getInstanceMethod(NSClassFromString(@"__NSArrayM"), originalSelector);
    Method replaceMethod = class_getInstanceMethod(NSClassFromString(@"__NSArrayM"), replaceSelector);
    
    BOOL didAddMethod = class_addMethod(NSClassFromString(@"__NSArrayM"), originalSelector, method_getImplementation(replaceMethod), method_getTypeEncoding(replaceMethod));
    
    if (didAddMethod) {
        class_replaceMethod(NSClassFromString(@"__NSArrayM"), replaceSelector, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
    } else {
        method_exchangeImplementations(originMethod, replaceMethod);
    }
}

// 实验有效,添加
- (void)safe_addObject:(id)obj {
//    NSLog(@"current method: %@", NSStringFromSelector(_cmd));
    NSAssert(obj != nil, @"can't add nil to NSMutableArray");
    [self safe_addObject:obj];
//    if (obj) {
//        [self safe_addObject:obj];
//    } else {
//        NSLog(@"can't add nil to NSMutableArray");
//    }
    [self objectAtIndex:0];
}

- (void)safe_removeObject:(id)obj {
//    NSLog(@"current method: %@", NSStringFromSelector(_cmd));
    NSAssert(obj != nil, @"can't remove nil to NSMutableArray");
    [self safe_removeObject:obj];
}

- (void)safe_insertObject:(id)obj atIndex:(NSInteger)index {
//    NSLog(@"current method: %@", NSStringFromSelector(_cmd));
    NSAssert(obj != nil, @"can't insert nil to NSMutableArray");
    NSAssert(index <= self.count, @"index beyond NSMutableArray count");
    [self safe_insertObject:obj atIndex:index];
}

- (void)safe_removeObjectAtIndex:(NSInteger)index {
//    NSLog(@"current method: %@", NSStringFromSelector(_cmd));
    NSAssert(index <= self.count, @"index beyond NSMutableArray count");
    [self safe_removeObjectAtIndex:index];
}

- (void)safe_objectAtIndex:(NSUInteger)index {
//    NSLog(@"current method: %@", NSStringFromSelector(_cmd));
    NSAssert(index <= self.count, @"index beyond NSMutableArray count");
    [self safe_objectAtIndex:index];
}


@end
